diff --git a/CMakeLists.txt b/CMakeLists.txt
index 53b401a..ccb289e 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -94,6 +94,7 @@ install(
     man/fvc_kerndisp.3
     man/fvc_open.3
     man/fvc_read.3
+    man/fvc_write.3
     DESTINATION "${CMAKE_INSTALL_MANDIR}/man3")
 
 install(
diff --git a/lib/fvc.c b/lib/fvc.c
index e6b96c1..cac7158 100644
--- a/lib/fvc.c
+++ b/lib/fvc.c
@@ -154,7 +154,7 @@ _fvc_open(fvc_t *kd, const char *uf, const char *mf, char *errout)
 		goto failed;
 	}
 
-	if ((kd->pmfd = open(mf, O_RDONLY | O_CLOEXEC, 0)) < 0) {
+	if ((kd->pmfd = open(mf, O_RDWR | O_CLOEXEC, 0)) < 0) {
 		_fvc_syserr(kd, kd->program, "%s", mf);
 		goto failed;
 	}
@@ -297,6 +297,47 @@ fvc_read(fvc_t *kd, fvc_addr_t kva, void *buf, size_t len)
 			_fvc_syserr(kd, kd->program, "fvc_read");
 			break;
 		}
+		printf("%% RD: %zu %d\n", pa, cc);
+		/*
+		 * If ka_kvatop returns a bogus value or our core file is
+		 * truncated, we might wind up seeking beyond the end of the
+		 * core file in which case the read will return 0 (EOF).
+		 */
+		if (cr == 0)
+			break;
+		cp += cr;
+		kva += cr;
+		len -= cr;
+	}
+
+	return (cp - (char *)buf);
+}
+
+ssize_t
+fvc_write(fvc_t *kd, fvc_addr_t kva, const void *buf, size_t len)
+{
+	int cc;
+	ssize_t cr;
+	off_t pa;
+	const char *cp;
+
+	cp = buf;
+	while (len > 0) {
+		cc = kd->arch->ka_kvatop(kd, kva, &pa);
+		if (cc == 0)
+			return (-1);
+		if (cc > (ssize_t)len)
+			cc = len;
+		errno = 0;
+		if (lseek(kd->pmfd, pa, 0) == -1 && errno != 0) {
+			_fvc_syserr(kd, 0, _PATH_MEM);
+			break;
+		}
+		cr = write(kd->pmfd, cp, cc);
+		if (cr < 0) {
+			_fvc_syserr(kd, kd->program, "fvc_write");
+			break;
+		}
 		/*
 		 * If ka_kvatop returns a bogus value or our core file is
 		 * truncated, we might wind up seeking beyond the end of the
@@ -331,3 +372,8 @@ fvc_kerndisp(fvc_t *kd)
 
 	return (kd->arch->ka_kerndisp(kd));
 }
+
+ssize_t xpread(int fd, void *buf, size_t count, off_t offset) {
+	printf("%% RD: %zu %zu\n", offset, count);
+	return pread(fd, buf, count, offset);
+}
diff --git a/lib/fvc.h b/lib/fvc.h
index 8680079..8cff17c 100644
--- a/lib/fvc.h
+++ b/lib/fvc.h
@@ -54,6 +54,8 @@ typedef unsigned char fvc_vm_prot_t;
 #define	FVC_VM_PROT_WRITE		((fvc_vm_prot_t) 0x02)
 #define	FVC_VM_PROT_EXECUTE		((fvc_vm_prot_t) 0x04)
 
+ssize_t xpread(int fd, void *buf, size_t count, off_t offset);
+
 struct fvc_page {
 	unsigned int	kp_version;
 	fvc_addr_t	kp_paddr;
@@ -76,6 +78,7 @@ fvc_t	 *fvc_open
 	    (const char *, const char *, char *,
 	    int (*)(const char *, fvc_addr_t *, void *), void *);
 ssize_t	  fvc_read(fvc_t *, fvc_addr_t, void *, size_t);
+ssize_t	  fvc_write(fvc_t *, fvc_addr_t, const void *, size_t);
 ssize_t   fvc_kerndisp(fvc_t *);
 
 typedef int fvc_walk_pages_cb_t(struct fvc_page *, void *);
diff --git a/lib/fvc_amd64.c b/lib/fvc_amd64.c
index 4d27998..69f1807 100644
--- a/lib/fvc_amd64.c
+++ b/lib/fvc_amd64.c
@@ -205,7 +205,7 @@ _amd64_vatop(fvc_t *kd, fvc_addr_t va, off_t *pa)
 		_fvc_err(kd, kd->program, "_amd64_vatop: pdpe_pa not found");
 		goto invalid;
 	}
-	if (pread(kd->pmfd, &pdpe, sizeof(pdpe), ofs) != sizeof(pdpe)) {
+	if (xpread(kd->pmfd, &pdpe, sizeof(pdpe), ofs) != sizeof(pdpe)) {
 		_fvc_syserr(kd, kd->program, "_amd64_vatop: read pdpe");
 		goto invalid;
 	}
@@ -237,7 +237,7 @@ _amd64_vatop(fvc_t *kd, fvc_addr_t va, off_t *pa)
 		_fvc_syserr(kd, kd->program, "_amd64_vatop: pde_pa not found");
 		goto invalid;
 	}
-	if (pread(kd->pmfd, &pde, sizeof(pde), ofs) != sizeof(pde)) {
+	if (xpread(kd->pmfd, &pde, sizeof(pde), ofs) != sizeof(pde)) {
 		_fvc_syserr(kd, kd->program, "_amd64_vatop: read pde");
 		goto invalid;
 	}
@@ -269,7 +269,7 @@ _amd64_vatop(fvc_t *kd, fvc_addr_t va, off_t *pa)
 		_fvc_err(kd, kd->program, "_amd64_vatop: pte_pa not found");
 		goto invalid;
 	}
-	if (pread(kd->pmfd, &pte, sizeof(pte), ofs) != sizeof(pte)) {
+	if (xpread(kd->pmfd, &pte, sizeof(pte), ofs) != sizeof(pte)) {
 		_fvc_syserr(kd, kd->program, "_amd64_vatop: read");
 		goto invalid;
 	}
diff --git a/lib/fvc_minidump_aarch64.c b/lib/fvc_minidump_aarch64.c
index 4b8477a..a1c5b42 100644
--- a/lib/fvc_minidump_aarch64.c
+++ b/lib/fvc_minidump_aarch64.c
@@ -86,7 +86,7 @@ _aarch64_minidump_initvtop(fvc_t *kd)
 		return (-1);
 	}
 	kd->vmst = vmst;
-	if (pread(kd->pmfd, &vmst->hdr, sizeof(vmst->hdr), 0) !=
+	if (xpread(kd->pmfd, &vmst->hdr, sizeof(vmst->hdr), 0) !=
 	    sizeof(vmst->hdr)) {
 		_fvc_err(kd, kd->program, "cannot read dump header");
 		return (-1);
diff --git a/lib/fvc_minidump_amd64.c b/lib/fvc_minidump_amd64.c
index 93e8238..0d2237f 100644
--- a/lib/fvc_minidump_amd64.c
+++ b/lib/fvc_minidump_amd64.c
@@ -126,7 +126,7 @@ _amd64_minidump_initvtop(fvc_t *kd)
 		return (-1);
 	}
 	kd->vmst = vmst;
-	if (pread(kd->pmfd, &vmst->hdr, sizeof(vmst->hdr), 0) !=
+	if (xpread(kd->pmfd, &vmst->hdr, sizeof(vmst->hdr), 0) !=
 	    sizeof(vmst->hdr)) {
 		_fvc_err(kd, kd->program, "cannot read dump header");
 		return (-1);
@@ -269,7 +269,7 @@ _amd64_minidump_vatop(fvc_t *kd, fvc_addr_t va, off_t *pa)
 				    (uintmax_t)a);
 				goto invalid;
 			}
-			if (pread(kd->pmfd, &pt, AMD64_PAGE_SIZE, ofs) !=
+			if (xpread(kd->pmfd, &pt, AMD64_PAGE_SIZE, ofs) !=
 			    AMD64_PAGE_SIZE) {
 				_fvc_err(kd, kd->program,
 				    "cannot read page table entry for %ju",
diff --git a/lib/fvc_minidump_i386.c b/lib/fvc_minidump_i386.c
index 61cc3db..b3ab955 100644
--- a/lib/fvc_minidump_i386.c
+++ b/lib/fvc_minidump_i386.c
@@ -94,7 +94,7 @@ _i386_minidump_initvtop(fvc_t *kd)
 		return (-1);
 	}
 	kd->vmst = vmst;
-	if (pread(kd->pmfd, &vmst->hdr, sizeof(vmst->hdr), 0) !=
+	if (xpread(kd->pmfd, &vmst->hdr, sizeof(vmst->hdr), 0) !=
 	    sizeof(vmst->hdr)) {
 		_fvc_err(kd, kd->program, "cannot read dump header");
 		return (-1);
diff --git a/lib/fvc_private.c b/lib/fvc_private.c
index 0069a54..fc798fe 100644
--- a/lib/fvc_private.c
+++ b/lib/fvc_private.c
@@ -130,7 +130,7 @@ _fvc_is_minidump(fvc_t *kd)
 {
 	char minihdr[8];
 
-	if (pread(kd->pmfd, &minihdr, 8, 0) == 8 &&
+	if (xpread(kd->pmfd, &minihdr, 8, 0) == 8 &&
 	    memcmp(&minihdr, "minidump", 8) == 0)
 		return (1);
 	return (0);
@@ -256,6 +256,7 @@ _fvc_pmap_get(fvc_t *kd, u_long idx, size_t len)
 
 	if ((off_t)off >= kd->pt_sparse_off)
 		return (NULL);
+	printf("%% RD: %zu %zu\n", kd->page_map_off+off, len);
 	return (void *)((uintptr_t)kd->page_map + off);
 }
 
@@ -270,8 +271,13 @@ _fvc_map_get(fvc_t *kd, u_long pa, unsigned int page_size)
 		return NULL;
 
 	addr = (uintptr_t)kd->page_map + off;
-	if (off >= kd->pt_sparse_off)
+	if (off >= kd->pt_sparse_off) {
+
 		addr = (uintptr_t)kd->sparse_map + (off - kd->pt_sparse_off);
+		printf("%% RD: %zu %u\n", off, page_size);
+	}
+	else
+		printf("%% RD: %zu %u\n", kd->page_map_off+off, page_size);
 	return (void *)addr;
 }
 
@@ -289,6 +295,7 @@ _fvc_pt_init(fvc_t *kd, size_t dump_avail_size, off_t dump_avail_off,
 	if (dump_avail_size > 0) {
 		kd->dump_avail = mmap(NULL, kd->dump_avail_size, PROT_READ,
 		    MAP_PRIVATE, kd->pmfd, dump_avail_off);
+		printf("%% RD: %zu %zu\n", dump_avail_off, dump_avail_size);
 	} else {
 		/*
 		 * Older version minidumps don't provide dump_avail[],
@@ -309,7 +316,7 @@ _fvc_pt_init(fvc_t *kd, size_t dump_avail_size, off_t dump_avail_off,
 		    map_len);
 		return (-1);
 	}
-	rd = pread(kd->pmfd, kd->pt_map, map_len, map_off);
+	rd = xpread(kd->pmfd, kd->pt_map, map_len, map_off);
 	if (rd < 0 || rd != (ssize_t)map_len) {
 		_fvc_err(kd, kd->program, "cannot read %zu bytes for bitmap",
 		    map_len);
diff --git a/man/fbsdvmcore.3 b/man/fbsdvmcore.3
index 4285ba2..c0d760c 100644
--- a/man/fbsdvmcore.3
+++ b/man/fbsdvmcore.3
@@ -89,4 +89,5 @@ etc.
 .Xr fvc_geterr 3 ,
 .Xr fvc_kerndisp 3 ,
 .Xr fvc_open 3 ,
-.Xr fvc_read 3
+.Xr fvc_read 3 ,
+.Xr fvc_write 3
diff --git a/man/fvc_geterr.3 b/man/fvc_geterr.3
index 964a097..7d74c25 100644
--- a/man/fvc_geterr.3
+++ b/man/fvc_geterr.3
@@ -66,7 +66,8 @@ or an error has not been captured for
 .Sh SEE ALSO
 .Xr fvc 3 ,
 .Xr fvc_close 3 ,
-.Xr fvc_read 3
+.Xr fvc_read 3 ,
+.Xr fvc_write 3
 .Sh BUGS
 This routine cannot be used to access error conditions due to a failed
 .Fn fvc_open
diff --git a/man/fvc_open.3 b/man/fvc_open.3
index 1f8e3be..4ea93ed 100644
--- a/man/fvc_open.3
+++ b/man/fvc_open.3
@@ -166,5 +166,6 @@ was
 .Xr fvc_geterr 3 ,
 .Xr fvc_native 3 ,
 .Xr fvc_read 3 ,
+.Xr fvc_write 3 ,
 .Xr kmem 4 ,
 .Xr mem 4
diff --git a/man/fvc_read.3 b/man/fvc_read.3
index 7413d59..c18dadc 100644
--- a/man/fvc_read.3
+++ b/man/fvc_read.3
@@ -36,18 +36,24 @@
 .Dt FVC_READ 3
 .Os
 .Sh NAME
-.Nm fvc_read
-.Nd read kernel virtual memory
+.Nm fvc_read ,
+.Nm fvc_write
+.Nd read or write kernel virtual memory
 .Sh LIBRARY
 .Lb libfbsdvmcore
 .Sh SYNOPSIS
 .In fvc.h
 .Ft ssize_t
 .Fn fvc_read "fvc_t *kd" "kvaddr_t addr" "void *buf" "size_t nbytes"
+.Ft ssize_t
+.Fn fvc_write "fvc_t *kd" "kvaddr_t addr" "void *buf" "size_t nbytes"
 .Sh DESCRIPTION
 The
 .Fn fvc_read
 function is used to read a crash dump file.
+.Fn fvc_write
+function is used to overwrite parts of a crash dump file.
+Note that only the fragments already present can be written.
 See
 .Fn fvc_open 3
 for information regarding opening kernel crash dumps.
@@ -63,6 +69,13 @@ to
 .Fa buf .
 .Pp
 The
+.Fn fvc_write
+function transfers
+.Fa nbytes
+bytes of data from
+.Fa buf
+to the kernel space address
+.Fa addr .
 .Sh RETURN VALUES
 Upon success, the number of bytes actually transferred is returned.
 Otherwise, -1 is returned.
diff --git a/man/fvc_write.3 b/man/fvc_write.3
new file mode 100644
index 0000000..f25fc74
--- /dev/null
+++ b/man/fvc_write.3
@@ -0,0 +1 @@
+.so man3/fvc_read.3
